from apps.common.base.views import *
from apps.interface.client.models import Client
from apps.pay.order.sceneHandle import payReturnScene
from apps.pay.wx.service import aes_ecb_pkcs7
import xmltodict
import xml.etree.ElementTree as et
from django.http import HttpResponse
from apps.pay.wx.function import getAuthorization, getSign, wx_decrypt, check_wx_cert

from apps.pay.order.dao import OrderDao
from project.settings import BASE_DIR

import decimal
import json
import traceback

from django.http import HttpResponse

class WxPayViewForV3Set(BaseViewSet):

    '''微信退款回调'''
    @action(methods=['post'], detail=False, authentication_classes=[], permission_classes=[])
    def returnbackforMinipro(self, request):
        global payment
        try:
            # 1.获得支付通知的参数
            body = request.body
            print('body', body)
            data = bytes.decode(body, 'utf-8')
            print('data', data)
            newdata = json.loads(data)
            print('newdata', newdata)

            # newdata = {
            #     "id": "EV-2018022511223320873",
            #     "create_time": "2018-06-08T10:34:56+08:00",
            #     "resource_type": "encrypt-resource",
            #     "event_type": "REFUND.SUCCESS",
            #     "summary": "退款成功",
            #     "resource": {
            #         "original_type": "refund",
            #         "algorithm": "AEAD_AES_256_GCM",
            #         "ciphertext": "...",
            #         "associated_data": "",
            #         "nonce": "..."
            #     }
            # }

            nonce = newdata['resource']['nonce']
            ciphertext = newdata['resource']['ciphertext']
            associated_data = newdata['resource']['associated_data']
            client_model = Client.objects.get(clientname='omall_minipro')
            try:
                payment = wx_decrypt(nonce, ciphertext, associated_data, client_model.mch_key)
            except Exception as e:
                print('e', e)
            if not payment:
                return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
            # payment = eval(payment.decode('utf-8'))
            zf_status = True if payment["trade_state"] == "SUCCESS" else False
            if zf_status:
                out_trade_no = payment['out_trade_no']
                order = OrderDao().findOneByOrderId(out_trade_no)
                if not order:
                    return HttpResponse({"code": "FAIL", "message": "失败，订单号不存在"}, status=400)
                # 处理业务
                # payReturnScene('wxpay', out_trade_no)
                return HttpResponse({"code": "SUCCESS", "message": "成功"}, status=200)
            else:
                return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
            # 7.回调报文签名验证
            # 同第一篇签名验证的代码
            # serial_num = '7AF7D718DF538D5B75CBA9F751E8D8CFA5FD7BEF'
            # wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate = check_wx_cert(
            #     request, client_model.mch_id, client_model.mch_key, serial_num)
            # if wechatpay_serial == serial_num:  # 应答签名中的序列号同证书序列号应相同
            #     # 8.获得回调报文中交易号后修改已支付订单状态
            #     # 9.项目业务逻辑
            #     return HttpResponse({"code": "SUCCESS", "message": "成功"})
            # else:
            #     # log.error(
            #     #     f"证书序列号比对失败【请求头中证书序列号：{wechatpay_serial}；本地存储证书序列号：{serial_num}；】")
            #     return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
        except Exception as e:
            # log.error(f"微信回调接口报错：{e},{traceback.format_exc()}")
            return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)

    '''微信退款接口'''
    @action(methods=['post'], detail=False)
    def refundsforMinipro(self, request):
        params = getRequestParams(request)
        if isEmptyStr(params.get('clientname')):
            return Response(response_message('clientname字段必填'))
        if not params.get("orderId"):
            return Response(response_message('orderId字段必填'))

        client_model = Client.objects.get(clientname=params.get('clientname'))
        _order = OrderDao().findOneByOrderId(params.get("orderId"))
        r_params = {}
        r_params['out_trade_no'] = _order.orderId
        r_params['out_refund_no'] = "T" + _order.orderId
        r_params['reason'] = params.get('reason') or '自主申请'
        r_params['notify_url'] = client_model.baseUrl + client_model.notify_url_return

        refund = 0
        total = 0
        if client_model.realPay > 0:
            refund = int(Decimal(client_model.realPay)*100)
            total = int(Decimal(client_model.realPay)*100)
        else:
            refund = int(Decimal(_order.realPay) * 100)
            total = int(Decimal(_order.realPay) * 100)

        if params.get('refund') and int(Decimal(params.get('refund')) * 100) > 0:
            refund = int(Decimal(params.get('refund')) * 100)

        r_params['amount'] = {
                              "refund": refund,
                              "total": total,
                              "currency": "CNY"
                            }

        print('r_params', r_params)

        _method = 'POST'
        _url_path = '/v3/refund/domestic/refunds'
        _serial_no = '7AF7D718DF538D5B75CBA9F751E8D8CFA5FD7BEF'
        _timestamp = str(round(datetime.datetime.now().timestamp()))
        _nonce_str = random_str(30)
        sign = getSign([_method, _url_path, _timestamp, _nonce_str, json.dumps(r_params)])
        # print("加密后子串：" + s)
        authorization = 'WECHATPAY2-SHA256-RSA2048 ' \
                        'mchid="{mchid}",' \
                        'nonce_str="{nonce_str}",' \
                        'signature="{sign}",' \
                        'timestamp="{timestamp}",' \
                        'serial_no="{serial_no}"'. \
                        format(
                            mchid=client_model.mch_id,
                            nonce_str=_nonce_str,
                            sign=sign,
                            timestamp=_timestamp,
                            serial_no=_serial_no
                        )
        print('authorization', authorization)
        refundsUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"
        # res_authorization = getAuthorization(params, r_params)
        headers = {'content-type': "application/json", 'Accept': "application/json",
                   'Authorization': authorization}
        cert_path = "{}/apps/pay/cert/apiclient_cert.pem".format(BASE_DIR)
        key_path = "{}/apps/pay/cert/apiclient_key.pem".format(BASE_DIR)

        res = requests.post(refundsUrl, data=json.dumps(r_params), headers=headers, cert=(cert_path, key_path))
        res_content = json.loads(res.content)
        print('res_content', res_content)
        if not res_content.get('refund_id'):
            return Response(response_message('退款失败'))

        return Response(response_success('退款成功'))


    '''支付异步回调'''
    @action(methods=['post'], detail=False, authentication_classes=[],permission_classes=[])
    def paybackforMinipro(self, request):
        global payment
        try:
            # 1.获得支付通知的参数
            body = request.body
            data = bytes.decode(body, 'utf-8')
            newdata = json.loads(data)

            # newdata = {
            #     "id": "96156edb-93dd-5e6e-808f-dd0e2a7c01ac",
            #     "create_time": "2024-05-30T16:38:43+08:00",
            #     "resource_type": "encrypt-resource",
            #     "event_type": "TRANSACTION.SUCCESS",
            #     "summary":"\xe6\x94\xaf\xe4\xbb\x98\xe6\x88\x90\xe5\x8a\x9f",
            #     "resource": {
            #         "original_type": "transaction",
            #         "algorithm": "AEAD_AES_256_GCM",
            #         "ciphertext": "kMIj3YhMJ1CSxmTxhK2TirlIjYQEOxQiq8o3gXqIa2jfEkcYynWCVUutEMCyiqSwDNo4YRRJ8dCUxZBEtr2jgP9TPJRuhyg36zsbGimiYf1m3cmFvgN2NiHS9WSKb/tdhCKP4bL+gyNzmk94WrikjF+8Ty0Iyq3aG+6Exy4gioyIke9Es6MDkqhju6SUrbLwb2atdYbLNAi5AbHBaPe3xC6uOR9txRN+QYrhr+4vnAmPe1Ksk9jnWnQq3gOLcYqHGQEh03RYIrArckxh5r7AtubopJ6JMcNWO2lt8Dd1pDWUFoNuLwYx+vZez6l4/ocqQSyELvT6iOTRAZ0jyb1T0vafpHiDdCaBPoSiIjsGSHAdFWJqqbP11wbI2gFySt1jmBh4ZNakpjMnagsiV4nDf/Wqf9XdV+78psGAlQICY8LrlvTC1zEZg8MfDHnYJ18/8fizIac7uLzqO9nvuBYEl/dNVAHqSQ8mkIrKedXXaB7LajfzFnBy4eXazIS9zKKXSS3D6xkbsUTmrIdI66U85/lFbhBzLK0s/K/IXFiGH92hVcraymXx3B1FUwQdYB3ST5gaCucovVg9l4kVqp0=",
            #         "associated_data": "transaction",
            #         "nonce": "nXeeQ5wQYzbs"
            #     }
            # }

            nonce = newdata['resource']['nonce']
            ciphertext = newdata['resource']['ciphertext']
            associated_data = newdata['resource']['associated_data']
            client_model = Client.objects.get(clientname='omall_minipro')
            try:
                payment = wx_decrypt(nonce, ciphertext, associated_data, client_model.mch_key)
            except Exception as e:
                print('e', e)
            if not payment:
                return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
            # payment = eval(payment.decode('utf-8'))
            zf_status = True if payment["trade_state"] == "SUCCESS" else False
            if zf_status:
                out_trade_no = payment['out_trade_no']
                order = OrderDao().findOneByOrderId(out_trade_no)
                if not order:
                    return HttpResponse({"code": "FAIL", "message": "失败，订单号不存在"}, status=400)
                if client_model.realPay == 0:
                    if int(Decimal(order.realPay) * 100) != int(payment["amount"]["payer_total"]):
                        return HttpResponse({"code": "FAIL", "message": "支付金额校验失败"}, status=400)
                payReturnScene('wxpay', out_trade_no)
                return HttpResponse({"code": "SUCCESS", "message": "成功"}, status=200)
            else:
                return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
            # 7.回调报文签名验证
            # 同第一篇签名验证的代码
            # serial_num = '7AF7D718DF538D5B75CBA9F751E8D8CFA5FD7BEF'
            # wechatpay_serial, wechatpay_timestamp, wechatpay_nonce, wechatpay_signature, certificate = check_wx_cert(
            #     request, client_model.mch_id, client_model.mch_key, serial_num)
            # if wechatpay_serial == serial_num:  # 应答签名中的序列号同证书序列号应相同
            #     # 8.获得回调报文中交易号后修改已支付订单状态
            #     # 9.项目业务逻辑
            #     return HttpResponse({"code": "SUCCESS", "message": "成功"})
            # else:
            #     # log.error(
            #     #     f"证书序列号比对失败【请求头中证书序列号：{wechatpay_serial}；本地存储证书序列号：{serial_num}；】")
            #     return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
        except Exception as e:
            # log.error(f"微信回调接口报错：{e},{traceback.format_exc()}")
            return HttpResponse({"code": "FAIL", "message": "失败"}, status=400)
    
    '''退款异步回调'''
    @action(methods=['post'], detail=False, authentication_classes=[],permission_classes=[])
    def returnbackforMinipro1(self, request):
        _xml = request.body
        #拿到微信发送的xml请求 即微信支付后的回调内容
        xml = str(_xml, encoding="utf-8")
        print("xml", xml)
        return_dict = {}
        tree = et.fromstring(xml)
        #xml 解析
        return_code = tree.find("return_code").text
        try:
            #拿到自己这次支付的 out_trade_no 
            # base64解码
            body = base64.b64decode(tree.find("req_info").text)
            # key做md5，得到32位小写key*
            key = '70ao7jnJhtICUk01drdTYWtkLUHqXzyf'
            key = hashlib.md5(key.encode("utf8")).hexdigest()
            # key*对加密串B做AES-256-ECB解密（PKCS7Padding）
            info = aes_ecb_pkcs7(body, key)
            tree = et.fromstring(info)
            _out_trade_no = tree.find("out_trade_no").text
            #这里省略了 拿到订单号后的操作 看自己的业务需求
            print('_out_trade_no', _out_trade_no)
            # payReturnScene(attach, 'wxpay', _out_trade_no)
            order = OrderDao().findOneByOrderId(_out_trade_no)
            if return_code == 'FAIL':
                # 官方发出错误
                return_dict['message'] = '退款失败'
                print('退款失败')
                #return Response(return_dict, status=status.HTTP_400_BAD_REQUEST)
                if order.orderStatus == 'RETURNING':
                    OrderDao().update(order.id, {'orderStatus': 'RETURN_FAIL'})
                return HttpResponse(return_dict, status=10001)
            elif return_code == 'SUCCESS':
                print('退款成功')
                if order.orderStatus == 'RETURNING':
                    OrderDao().update(order.id, {'orderStatus': 'HAS_RETURN'})
                
        except Exception as e:
            pass
        finally:
            return HttpResponse(return_dict, status=200)

    '''小程序预下单接口'''
    @action(methods=['post'], detail=False)
    def createWxPayforMinipro(self, request):
        params = getRequestParams(request)
        if isEmptyStr(params.get('openid')):
            return Response(response_message('openid字段必填'))
        if isEmptyStr(params.get('clientname')):
            return Response(response_message('clientname字段必填'))
        if not params.get("orderId"):
            return Response(response_message('orderId字段必填'))
            
        client_model = Client.objects.get(clientname=params.get('clientname'))
        _order = OrderDao().findOneByOrderId(params.get("orderId"))
        if isEmptyStr(_order.scene):
            return Response(response_message('该订单异常，缺少scene参数'))

        # 校验积分
        if _order.realPayIncomes > 0:
            if request.user.incomes < _order.realPayIncomes:
                return Response(response_modalMessage('积分不足，支付失败'))

        r_params={}
        r_params["mchid"] = client_model.mch_id
        r_params["appid"] = client_model.appid
        r_params["description"] = "商品购买"
        r_params["out_trade_no"] = params.get("orderId")
        r_params['attach'] = client_model.clientname
        r_params["notify_url"] = client_model.baseUrl + client_model.notify_url
        r_params["payer"] = {
            "openid": params.get('openid')
        }
        realPay = 0
        if client_model.realPay > 0:
            realPay = Decimal(client_model.realPay)
        else:
            realPay = _order.realPay
        
        r_params["amount"] = {
            "total": int(Decimal(realPay) * 100),
            "currency": "CNY"
        }

        _method = 'POST'
        _url_path = '/v3/pay/transactions/jsapi'
        _serial_no = '7AF7D718DF538D5B75CBA9F751E8D8CFA5FD7BEF'
        _timestamp = str(round(datetime.datetime.now().timestamp()))
        _nonce_str = random_str(30)
        sign = getSign([_method, _url_path, _timestamp, _nonce_str, json.dumps(r_params)])
        # print("加密后子串：" + s)
        authorization = 'WECHATPAY2-SHA256-RSA2048 ' \
                        'mchid="{mchid}",' \
                        'nonce_str="{nonce_str}",' \
                        'signature="{sign}",' \
                        'timestamp="{timestamp}",' \
                        'serial_no="{serial_no}"'. \
                        format(
                            mchid=r_params.get('mchid'),
                            nonce_str=_nonce_str,
                            sign=sign,
                            timestamp=_timestamp,
                            serial_no=_serial_no
                        )
        wxPayOrderUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
        headers = {'content-type': "application/json", 'Accept': "application/json", 'Authorization': authorization}
        cert_path = "{}/apps/pay/cert/apiclient_cert.pem".format(BASE_DIR)
        key_path = "{}/apps/pay/cert/apiclient_key.pem".format(BASE_DIR)

        res = requests.post(wxPayOrderUrl, data=json.dumps(r_params), headers=headers, cert=(cert_path, key_path))
        res_content = json.loads(res.content)
        print('res_content', res_content)
        r_data = {}
        if not res_content.get('prepay_id'):
            return Response(response_message('支付失败'))
        prepay_id = res_content.get('prepay_id')
        timestamp = str(round(datetime.datetime.now().timestamp()))
        nonce_str = random_str(30)
        package = "prepay_id=" + prepay_id
        sign = getSign([r_params.get('appid'), timestamp, nonce_str, package])
        # 5个参数
        r_data["appId"] = r_params.get('appid')
        r_data["nonceStr"] = nonce_str
        r_data["package"] = package
        r_data["timeStamp"] = timestamp
        r_data["signType"] = "RSA"
        r_data["paySign"] = sign
        return Response(response_success(r_data))


    '''APP预下单接口'''
    @action(methods=['post'], detail=False)
    def createWxPayforApp(self, request):
        params = getRequestParams(request)
        if isEmptyStr(params.get('openid')):
            return Response(response_message('openid字段必填'))
        if isEmptyStr(params.get('clientname')):
            return Response(response_message('clientname字段必填'))
        if not params.get("orderId"):
            return Response(response_message('orderId字段必填'))
        
        client_model = Client.objects.get(clientname=params.get('clientname'))
        _order = OrderDao().findOneByOrderId(params.get("orderId"))
        if isEmptyStr(_order.scene):
            return Response(response_message('该订单异常，缺少scene参数'))

        r_params={}
        r_params["mch_id"] = client_model.mch_id
        r_params["appid"] = client_model.appid
        r_params["openid"] = params.get('openid')
        r_params["nonce_str"] = random_str(32)
        r_params["sign_type"] = "MD5"
        r_params["body"] = "商品购买"
        r_params['attach'] = _order.scene
        r_params["out_trade_no"] = params.get("orderId") # + random_num(5) #每次传给微信的订单号都随机，为了处理不同渠道的未支付的订单
        r_params["notify_url"] = client_model.baseUrl + client_model.notify_url
        r_params["trade_type"] = "APP"

        realPay = 0
        if client_model.realPay > 0:
            realPay = Decimal(client_model.realPay)
        else:
            _order = OrderDao().findOneByOrderId(params.get("orderId"))
            realPay = _order.realPay
        r_params["total_fee"] = int(Decimal(realPay) * 100)

        print('r_params', r_params)
        wxPayOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        r_params["sign"]=getSign(r_params, client_model.mch_key)
        data = {'root': r_params}
        xml = xmltodict.unparse(data)
        res = requests.post(wxPayOrderUrl, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
        xmlmsg = xmltodict.parse(res.text)

        r_data = {}
        # 获取prepay_id
        if xmlmsg['xml']['return_code'] == 'SUCCESS':
            if xmlmsg['xml']['result_code'] == 'SUCCESS':
                prepay_id = xmlmsg['xml']['prepay_id']
                # 5个参数

                r_data["appid"] = xmlmsg['xml']['appid']
                r_data["noncestr"] = xmlmsg['xml']['nonce_str']
                r_data["package"] = "Sign=WXPay"
                r_data["partnerid"] = client_model.mch_id
                r_data["prepayid"] = prepay_id
                r_data["timestamp"] = str(datetime.datetime.now().timestamp())
                r_data["sign"]=getSign(r_data, client_model.mch_key)
                print('r_data', r_data)
            else:
                print('return_msg', xmlmsg['xml']['err_code_des'].encode('raw_unicode_escape').decode('utf-8'))
        else:
            print('return_msg', xmlmsg['xml']['return_msg'].encode('raw_unicode_escape').decode('utf-8'))
        return Response(response_success(r_data))
